#include "stdafx.h"
#include "UModelViewer.h"
#include "UModel.h"
#include "UGLFont.h"
#include "UStringUtils.h"
#include "UArcBall.h"
#include "UDockable.h" //For gluProject override (FIXME)

/* Read for UModelViewer.h for inspiration */

TModelViewer::TModelViewer(TModel* mdl): TCustomWindow(true) {
	model = boost::shared_ptr<TModel>(mdl);
	scale = 1;
	autoRotate = false;
	wireframe = false;
	lighting = true;
	rotatingModel = false;
	orthoMode = false;
	mx=0;
	my=0;
	camera = TCamera(TVector(0.0, 1.8, 3.0), TVector(0.0, 1.8, 0.0), TVector(0.0, 1.0, 0.0));
	modelPos.x    =   0.0;
	modelPos.y    =   0.0;
	modelPos.z    =   0.0;
	modelRot.x    =   0.0;
	modelRot.y    =   0.0;
	modelRot.z    =   0.0;
	lightPos.x    =  100.0;
	lightPos.y    =  100.0;
	lightPos.z    =  100.0;
}

void TModelViewer::resize(int w, int h) { //For knowing our own width and hight
	windowWidth = w;
	windowHeight = h;
}

void TModelViewer::Draw() {
	glClearColor(0,0,0,0);
	glClear(GL_COLOR_BUFFER_BIT);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(48.0, float(windowWidth)/float(windowHeight), 1.0, 100.0); // fovy, aspect, zNear, zFar
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	camera.apply();

	glEnable(GL_CULL_FACE);
	if(lighting) {
	/* Set GL_LIGHT_0's position to something like 45 degrees to the 'vertical'. Coordinate (1,1,0) should work nicely
	 * in most cases. Don't set any other glLight or glLightModel options - just let them default. Enable GL_LIGHTING
	 * and GL_LIGHT_0. Set the glColor to whatever colour you want each polygon to basically appear to be. That sets the
	 * Ambient and Diffuse to the same value which is what you generally want.
	 */
		glBegin(GL_QUADS);
			glColor3f(1.0, 0.0, 1.0);
			glVertex3f(lightPos.x + -0.25,lightPos.y + 0,lightPos.z + -0.25);
			glVertex3f(lightPos.x + -0.25,lightPos.y + 0,lightPos.z +  0.25);
			glVertex3f(lightPos.x +  0.25,lightPos.y + 0,lightPos.z +  0.25);
			glVertex3f(lightPos.x +  0.25,lightPos.y + 0,lightPos.z + -0.25);

			glVertex3f(lightPos.x + 0,lightPos.y + -0.25,lightPos.z + -0.25);
			glVertex3f(lightPos.x + 0,lightPos.y + -0.25,lightPos.z +  0.25);
			glVertex3f(lightPos.x + 0,lightPos.y +  0.25,lightPos.z +  0.25);
			glVertex3f(lightPos.x + 0,lightPos.y +  0.25,lightPos.z + -0.25);

			glVertex3f(lightPos.x + -0.25,lightPos.y + -0.25,lightPos.z + 0);
			glVertex3f(lightPos.x + -0.25,lightPos.y +  0.25,lightPos.z + 0);
			glVertex3f(lightPos.x +  0.25,lightPos.y +  0.25,lightPos.z + 0);
			glVertex3f(lightPos.x +  0.25,lightPos.y + -0.25,lightPos.z + 0);
		glEnd();

		glEnable(GL_LIGHTING);
		glEnable(GL_LIGHT0);
		GLfloat LightPosition[] = { lightPos.x, lightPos.y, lightPos.z, 1.0f };
		glLightfv(GL_LIGHT0, GL_POSITION, LightPosition);
		glShadeModel(shadeModel);
	}


	glDisable(GL_CULL_FACE);
	glDisable(GL_LIGHTING);
	glBegin(GL_QUADS); //Draw a floor plane
		glColor3f(0.0, 0.0, 0.0);
		glNormal3f(0.0, 1.0, 0.0);
		glVertex3f(-100.0, 0.0, -100.0);

		glColor3f(0.125, 0.125, 0.125);
		glNormal3f(0.0, 1.0, 0.0);
		glVertex3f(100.0, 0.0, -100.0);

		glColor3f(0.5, 0.5, 0.5);
		glNormal3f(0.0, 1.0, 0.0);
		glVertex3f(100.0, 0.0, 100.0);

		glColor3f(0.5, 0.5, 0.5);
		glNormal3f(0.0, 1.0, 0.0);
		glVertex3f(-100.0, 0.0, 100.0);
	glEnd();
	glEnable(GL_LIGHTING);
	glEnable(GL_CULL_FACE);


	glPushMatrix();
	glRotatef(modelRot.x, 1, 0, 0);
	glRotatef(modelRot.y, 0, 1, 0);
	glRotatef(modelRot.z, 0, 0, 1);
	glColor3f(1.0, 1.0, 1.0);
	if(wireframe)
		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
// 	glEnable(GL_NORMALIZE);//delete this line once normals in the SMD loader work properly
//	glScalef(scale, scale, scale);
	glScalef(0.03, 0.03, 0.03); //FIXME: HACK
	model->draw(1);

	TVector modelScreenPos;
	if(rotatingModel) {
// 		modelScreenPos = Parent->gluProject(modelPos);
// 		projectPoint(modelPos, gluRenderParams &params, TDockable * window = NULL);
	}
	glPopMatrix();

	/* ArcBall stuff */
	if(arcball)
		arcball->draw();
	/*
	GLint matrixMode;
	glGetIntegerv(GL_MATRIX_MODE, &matrixMode);
	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
// 	glLoadIdentity();
	glOrtho(0, 1, 1, 0, -1,1);
	glMatrixMode(GL_MODELVIEW);
	TVector fp;// = Parent->gluProject(model->getFurthestPoint());
	glMatrixMode(GL_PROJECTION);
	glPopMatrix();
	glMatrixMode(matrixMode);
	if(rotatingModel) {
		TArcBall arcball(windowWidth, windowHeight, modelScreenPos.x, modelScreenPos.y, modelScreenPos<=fp);
		arcball.draw();
	}

// 	if(mstate==1) { //LMB
// 		TArcBall arcball;
// 		modelRot.y += ((float)dx);
// 		modelRot.x += ((float)dy);
// 		modelRot.z += ((float)dx+(float)dy)/2.0f;
// 		TArcBall(windowWidth, windowHeight, windowCoords[0], windowCoords[1], );
// 	}

	/* Print some stats * /
	glDisable(GL_LIGHTING);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(0, windowWidth, windowHeight, 0, -1,1);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glDisable(GL_CULL_FACE);
	glColor4f(1.0, 0.0, 1.0,0.5);
	glDisable(GL_DEPTH_TEST);
	glDisable(GL_BLEND);
	glColor4f(1,1,0,1);
	fnt->drawText(3, 0, STRFORMAT("\
Light position: (%4.2f, %4.2f, %4.2f)\n\
Model position: (%4.2f, %4.2f, %4.2f)\n\
Model rotation: (%4.2f, %4.2f, %4.2f)\n\
Model Screen Pos: (%4.2f, %4.2f, %4.2f)\n\
Model FP: (%4.2f, %4.2f, %4.2f)\n\
", lightPos.x, lightPos.y, lightPos.z\
 , modelPos.x, modelPos.y, modelPos.z\
 , modelRot.x, modelRot.y, modelRot.z\
 , modelScreenPos.x, modelScreenPos.y, modelScreenPos.z\
 , fp.x, fp.y, fp.z\
   ));
//Camera position: (%4.2f, %4.2f, %4.2f)\n\ , cameraPos.x, cameraPos.y, cameraPos.z\
	/* Frame based updates */
		if(autoRotate) {
		modelRot.x += 0.1;
		modelRot.y += 0.2;
		modelRot.z += 0.05;
	}
}

void TModelViewer::MouseMove(int x, int y, int mstate) { //for arcball
	oldmx = mx;
	oldmy = my;
	mx = x;
	my = y;
	mdx = oldmx - mx;
	mdy = oldmy - my;
	switch(mstate) {
		case SDL_BUTTON_LEFT: {
			if(arcball) {
// 				arcball->update(x,y);
// 				camera.rotate(GLfloat& x, GLfloat& y, GLfloat& z);
			}
		}; break;
		case SDL_BUTTON_MIDDLE: {
			camera.translate(TVector(float(mdx)/float(windowWidth)*2.0, float(mdy)/float(windowHeight)*2.0, 0));
		}; break;
	}
}

void TModelViewer::MouseDown ( int X, int Y, uint8 button ) {
	if(button == SDL_BUTTON_LEFT) {
		cout << (modelPos <= camera.getPosition()) << "\n";
		arcball = boost::shared_ptr<TArcBall>(new TArcBall(windowWidth, windowHeight, X, Y, modelPos <= camera.getPosition()));
	}
}

void TModelViewer::MouseUp(int X, int Y, uint8 button) {
	switch(button) {
		case SDL_BUTTON_WHEELDOWN: {
			TVector t(camera.getLookat());
			t.Normalize() *= -0.1f;
			camera.translate(t);
		}; break;
		case SDL_BUTTON_WHEELUP: {
			TVector t(camera.getLookat());
			t.Normalize() *= 0.1f;
			camera.translate(t);
		}; break;
		case SDL_BUTTON_LEFT: {
			arcball.reset();
		}; break;
	}
}

void TModelViewer::KeyDown(SDL_KeyboardEvent* Key) {
	switch(Key->keysym.sym) {
		case SDLK_r:
			autoRotate = !autoRotate;
			break;
		case SDLK_l:
			lighting = !lighting;
			break;
		case SDLK_w:
			wireframe = !wireframe;
			break;
		case SDLK_s:
			shadeModel=(shadeModel==GL_FLAT)? GL_SMOOTH : GL_FLAT;
			break;
		case SDLK_o:
			orthoMode = !orthoMode;
			break;
		default:
			break;
	}
}

